#pragma once

#include <list>
#include <map>
#include <string>
#include <windows.h>

using namespace std;

namespace TinyCC{
	namespace msg{

		struct CTinyMsgHeader
		{
		public:
			CTinyMsgHeader():m_magicID(0x3333),m_msgIndex(0),m_msgItem(0),m_sourcePort(0),m_defaultParamCount(0),m_ExternalParamMapCount(0),m_checkSum(0)
			{
				memset(&m_sourceIP,0,4*sizeof(unsigned char));
			}

			~CTinyMsgHeader()
			{
			}

			WORD		m_magicID;					//magic id = 0x3333
			WORD		m_msgIndex;					// message type
			WORD		m_msgItem;					// message name
			BYTE		m_sourceIP[4];				// source IP
			WORD		m_sourcePort;				// source port
			WORD		m_defaultParamCount;		
			WORD		m_ExternalParamMapCount;	
			WORD		m_checkSum;					// check sum ,located in the head and the end of message to verify the message
		};


		//Define the data structure of metadata related the operation
		class CTinyMetaElement
		{
		public:
			CTinyMetaElement(const char* pData,DWORD dataLen):m_pData(NULL),m_dwLength(dataLen)
			{
				m_pData = new char[ dataLen + 1 ]; 
				memcpy(m_pData,pData,dataLen);
				m_pData[dataLen]=0;
			};

			//Copy constructor function use deep copy
			CTinyMetaElement(CTinyMetaElement& value)
			{
				if(&value==this)
					return;
				if(m_pData!=NULL)
					delete[] m_pData;

				m_dwLength=value.m_dwLength;

				m_pData  = new char[ m_dwLength ];
				memcpy(m_pData,value.m_pData,m_dwLength);
			};

			~CTinyMetaElement()
			{
				if(m_pData!=NULL)
				{
					delete[] m_pData;
					m_pData = NULL;
				}
			};

			friend bool operator==(const CTinyMetaElement& left,const CTinyMetaElement& right)
			{
				return (left.m_dwLength==right.m_dwLength) && (memcmp(left.m_pData,right.m_pData,left.m_dwLength) == 0); 
			}

			inline bool isEqual(CTinyMetaElement* value)
			{
				if(value!=NULL)
					return (m_dwLength==value->getDataLength()) && (memcmp(m_pData,value->getData(),value->getDataLength())==0);
				else
					return false;
			}

			inline DWORD getDataLength() const {	return m_dwLength;	}
			inline char* getData() const 
			{
				if(m_dwLength==0)
					return NULL;
				else
					return m_pData;	
			}

			inline long getSerializeSize() const 
			{
				return sizeof(DWORD)+m_dwLength;
			}

			void serialize(const char* data,long &length)
			{
				char* p=(char*)data;
				length=0;
				//A DWORD memory required to store the length of metadata
				memcpy(p,&m_dwLength,sizeof(DWORD));
				p=p+sizeof(DWORD);
				length+=sizeof(DWORD);
				//Copy data
				memcpy(p,m_pData,m_dwLength);
				length+=m_dwLength;
			}

		private:
			DWORD		m_dwLength;		//length of data(byte)
			char*		m_pData;		// data
		};

		class CTinyMetaElementSet
		{
		public:
			//Parameter of Construnctor function is the key value and it's length
			inline CTinyMetaElementSet(CTinyMetaElement* key):m_serializeSize(0)
			{
				//CTinyMetaElement* pMValue=new CTinyMetaElement(pData,dataLen);
				if(key!=NULL)
				{
					m_elementSetKey=key;
					m_serializeSize=sizeof(WORD);	//Take one WORD to store metadata's value
					m_serializeSize+=key->getSerializeSize();//zeof(DWORD)/*store lenght of KEY*/+dataLen;
				}
			};

			inline ~CTinyMetaElementSet()
			{
				//free key mem
				delete m_elementSetKey;
				//free value mem
				CTinyMetaElement* pValue=NULL;
				std::list<CTinyMetaElement*>::iterator itEnum=m_elementSetValueList.begin();
				while(itEnum!=m_elementSetValueList.end()){
					pValue=*itEnum;
					if(pValue!=NULL)
						delete pValue;
					itEnum++;
				}//while
			}

			inline DWORD getSerializeSize(){	return m_serializeSize;	}

			inline long getValueCount(){	return 	static_cast<long>(m_elementSetValueList.size()-1);	}

			//Check if input data is equal to Key
			inline bool isKeyEqual(CTinyMetaElement* key)	
			{
				if(m_elementSetKey!=NULL)
					return m_elementSetKey->isEqual(key);
				else
					return false;
			}

			inline long pushValue(CTinyMetaElement* value)
			{
				if(value==NULL)
					return -1;
				m_elementSetValueList.push_back(value);
				m_serializeSize+=value->getSerializeSize();//sizeof(DWORD)/*Take one DWORD to store the lenght of metadata*/+valueLength;
				return static_cast<long>(m_elementSetValueList.size()-1);
			}

			CTinyMetaElement* getKey() 
			{
				if(m_elementSetKey!=NULL)
				{
					return m_elementSetKey;
				}
				return NULL;
			}

			CTinyMetaElement* getValue(int elementValueIndex)
			{
				std::list<CTinyMetaElement*>::iterator itFindValue=m_elementSetValueList.begin();
				while(itFindValue!=m_elementSetValueList.end())
				{
					if(elementValueIndex==0&&(*itFindValue)!=NULL)
					{
						return (*itFindValue);
					}
					elementValueIndex--;
					itFindValue++;
				}//while
				return NULL;
			}

			void serialize(const char* data,long &length);
			bool deSerialize(char *pMsg,long valueNumber,long& dwLength);
		private:
			inline void _incLength(long& length,size_t incSize,long maxLength)
			{
				if(length + static_cast< long >( incSize )>maxLength)
				{
					return;
				}
				length += static_cast< long >( incSize );
			}

		private:
			std::list<CTinyMetaElement*>	m_elementSetValueList;	// metaValue List
			CTinyMetaElement *              m_elementSetKey;
			long                            m_serializeSize;	//message length after serialization
		};

		class CTinyParamMap
		{
		public:
			CTinyParamMap(WORD EPIndex):m_EPIndex(EPIndex)
			{};
			~CTinyParamMap()
			{
				CTinyMetaElementSet* pMVCluster=NULL;
				std::map< std::string,CTinyMetaElementSet* >::iterator itEnum=m_namedParamList.begin();
				while(itEnum!=m_namedParamList.end())
				{
					pMVCluster=itEnum->second;
					if(pMVCluster!=NULL)
						delete pMVCluster;
					itEnum++;
				}//while
			};

			long pushParam(CTinyMetaElement* key, CTinyMetaElement* value);
			inline long getParamCount() const{ return static_cast< long >( m_namedParamList.size() ); }
			CTinyMetaElement* getParamKey(int namedParamIndex);
			int getParamValueCount(CTinyMetaElement* key);
			int getParamValueCount(const char* key)
			{
				std::string keystr=key;
				CTinyMetaElement* keytemp=new CTinyMetaElement(keystr.c_str(),(DWORD)keystr.size());
				int result= getParamValueCount(keytemp);
				delete keytemp;
				return result;
			}
			int getParamValueCount(int keyIndex);                     //for dump msgs by index;
			CTinyMetaElement* getParamValue(CTinyMetaElement* key,int ParamValueIndex);
			CTinyMetaElement* getParamValue(int keyIndex,int ParamValueIndex);

			long getSerializeSize();
			void serialize(const char* data,long &length);	
			bool deSerialize(char *pMsg,long& length);

		private:
			inline void _incLength(long& length,size_t incSize,long maxLength)
			{
				if(length+(int)incSize>maxLength)
				{
					return;
				}
				length+=(long/* added for warning*/)incSize;
			}
		private:
			WORD				m_EPIndex;			                    // index of Externel parameter cluster
			std::map<std::string,CTinyMetaElementSet*>	m_namedParamList;	// Externel parameter list
		};


	}
}
